/**
 * @author Tobias Boehm
 *
 * 25.03.2011
 */
package org.anddev.andengine.extension.tbsengine.resource;

import java.util.HashSet;

import org.anddev.andengine.extension.tbsengine.match.gamestate.AbsGlobalGameState.IGameStateElement;

/**
 * A resource account is the basic way to represent the value of a specific 
 * resource in a game. Resource accounts could have limits for their minimum 
 * or/and maximum value. 
 * <p>
 * Manual:<br>
 * You have to register {@link IResourceAmountChangedListener} in order to 
 * inform game objects or view components about value changes.
 * <br>
 * You have to call {@link #transact(int)} in order to add or withdraw values 
 * from the account. If the account has limits this method may throw an {@link ResourceAccountLimitExceededException}
 * if you try to add or remove more than possible. This is why you should check {@link #hasAmountMAX()} or/and {@link #hasAmountMIN()}
 * first.
 *
 * 
 * @see AbsBaseResourceType 
 * @see IResourceAmountChangedListener
 * 
 * @author Tobias Boehm
 *
 */
public class ResourceAccount implements IGameStateElement{

	private final HashSet<IResourceAmountChangedListener> mResourceAmountChangedListeners;
	private final AbsBaseResourceType mResourceType;
	private int mResourceAmount;
	private Integer mAmountMAX;
	private Integer mAmountMIN;
	
	public ResourceAccount(final AbsBaseResourceType pResourceType){
		
		this(pResourceType, null, null);
	}
	
	public ResourceAccount(final AbsBaseResourceType pResourceType, final Integer pAmountMin, final Integer pAmountMax){
		
		this(pResourceType,pAmountMin,pAmountMax,0);
	}
	
	public ResourceAccount(final AbsBaseResourceType pResourceType, final Integer pAmountMin, final Integer pAmountMax, final int pStartAmount){
		
		this.mAmountMAX = pAmountMax;
		this.mAmountMIN = pAmountMin;
		this.mResourceType = pResourceType;
		this.mResourceAmount = pStartAmount;
		this.mResourceAmountChangedListeners = new HashSet<IResourceAmountChangedListener>();
	}
	
	public AbsBaseResourceType getResourceType(){
		
		return this.mResourceType;
	}
		
	public synchronized void transact(final int pAmountChange) throws ResourceAccountLimitExceededException{
		
		int tmpAmount = this.mResourceAmount + pAmountChange;
		
		if((this.hasAmountMIN() && (this.mAmountMIN > tmpAmount)) ||
		   (this.hasAmountMAX() && (this.mAmountMAX < tmpAmount))){
			
			throw new ResourceAccountLimitExceededException();
		}
		
		final int difference = tmpAmount - this.mResourceAmount;
		
		this.mResourceAmount = tmpAmount;
		
		this.onAmountChange(difference);
	}
	
	protected void onAmountChange(final int pAmountChange){
	
		for(IResourceAmountChangedListener currentChangeListener : this.mResourceAmountChangedListeners){
			
			currentChangeListener.onAmountChanged(this.mResourceAmount, pAmountChange);
		}
	}
	
	
	public boolean registerResourceAmountChangedListener(final IResourceAmountChangedListener pResourceAmountChangedListener){
		
		return this.mResourceAmountChangedListeners.add(pResourceAmountChangedListener);
	}
	
	public boolean unregisterResourceAmountChangedListener(final IResourceAmountChangedListener pResourceAmountChangedListener){
		
		return this.mResourceAmountChangedListeners.remove(pResourceAmountChangedListener);
	}
	
	public boolean hasAmountMAX(){
		
		return (this.mAmountMAX != null);
	}
	
	public boolean hasAmountMIN(){
		
		return (this.mAmountMIN != null);
	}
	
	public int getCreditLine() {
		
		if(this.mAmountMIN != null){
			
			return (this.mResourceAmount - this.mAmountMIN);
		
		}else{
					
			return mResourceAmount;
		}
	}
	
	public int getResourceAmount(){
		
		return mResourceAmount; 
	}

	public Integer getAmountMAX() {
		return mAmountMAX;
	}

	public Integer getAmountMIN() {
		return mAmountMIN;
	}

	public void setAmountMAX(final int pAmountMAX) {
		this.mAmountMAX = pAmountMAX;
	}

	public void setAmountMIN(final int pAmountMIN) {
		this.mAmountMIN = pAmountMIN;
	};
	
	public void removeAmountMAX(){
		
		this.mAmountMAX = null;
	}
	
	public void removeAmountMIN(){
		
		this.mAmountMIN = null;
	}
	
	public interface IResourceAmountChangedListener {
		
		public void onAmountChanged(final int pNewAmount, final int pAmountChange);
		
	}
}
